use unicode_width::UnicodeWidthStr;

use crate::prelude::ByteIdx;

// 终端默认制表位间隔（每4列一个Tab Stop）
const TAB_STOP: usize = 4;

// 图元渲染时宽度
#[derive(Clone, Copy, Debug)]
pub enum GraphicCellWidth {
    // 零宽字符，本身没有视觉宽度的图元，不占用终端列宽，保留但不渲染。
    Zero,
    Half,
    Full,
    // tab的宽度可能= 1，2，3，4
    TabStop3,
    TabStop4,
}

impl GraphicCellWidth {
    pub fn to_usize(&self) -> usize {
        match self {
            Self::Zero => 0,
            Self::Half => 1,
            Self::Full => 2,
            Self::TabStop3 => 3,
            Self::TabStop4 => 4,
        }
    }

    pub fn from_usize(width: usize) -> Self {
        match width {
            0 => Self::Zero,
            1 => Self::Half,
            2 => Self::Full,
            3 => Self::TabStop3,
            4 => Self::TabStop4,
            // 宽度为5及5以上的都转为全宽
            _ => Self::Full,
        }
    }
}

// 图形单元，代表一个任意宽度的字符，简称：Cell。在 unicode-segmentation 中称为 grapheme 字素。
#[derive(Clone)]
pub struct GraphicCell {
    // 图元的内容，终端将其渲染为视觉上的一个字符。
    pub content: String,
    // 图元的渲染时宽度，用于终端渲染时确定宽度。
    pub rendering_width: GraphicCellWidth,
    // 图元的渲染替代字符串，用于终端渲染时替代该图形单元，常用于有宽度的控制字符， 如 \t。
    pub replacement: Option<String>,
    // 图元在一行中的“字节”索引起始位置
    pub start: ByteIdx,
}

impl GraphicCell {}

impl GraphicCell {
    // 计算制表符的替代空格数（需传入当前列位置）
    fn get_tab_spaces(current_col: usize) -> (String, GraphicCellWidth) {
        // 计算到下一个Tab Stop需要的空格数
        let spaces_needed = TAB_STOP - (current_col % TAB_STOP);
        // 生成对应数量的空格字符串
        let replacement = " ".repeat(spaces_needed);

        // 转换为图元的渲染宽度
        let rendering_width = GraphicCellWidth::from_usize(spaces_needed);
        (replacement, rendering_width)
    }

    /// 针对不同的字素，返回替代字符以及渲染宽度
    /// - current_col: 当前终端列位置（用于计算制表符的宽度）
    fn get_replacement(grapheme: &str, current_col: usize) -> Option<(String, GraphicCellWidth)> {
        let width = grapheme.width();
        match grapheme {
            // 普通空格 → 替换为 ␣（可视化空白符）
            " " => Some(("␣".to_string(), GraphicCellWidth::Half)),
            // 制表符 → 根据当前列位置返回对应数量的空格
            "\t" => {
                let (replacement, rendering_width) = Self::get_tab_spaces(current_col);
                Some((replacement, rendering_width))
            }
            // 非普通空格的空白符（全角空格等）→ 替换为 ␣（可视化空白符）
            _ if width > 0 && grapheme.trim().is_empty() => {
                Some(("␣".to_string(), GraphicCellWidth::Half))
            }
            // 零宽度字符（控制字符等），只保留不替换。
            _ if width == 0 => None,
            // 普通可见字符 → 不替换
            _ => None,
        }
    }

    /// 将单个字素转换为 GraphicCell
    /// - grapheme: 待转换的字素（视觉上的单个字符）
    /// - start: 该字素在原字符串中的字节起始索引（GraphicCell 的 start 字段）
    /// - current_col: 当前终端列位置（用于计算制表符的宽度）
    pub fn grapheme_to_cell(grapheme: &str, start: ByteIdx, current_col: usize) -> GraphicCell {
        let (replacement, rendering_width) = match Self::get_replacement(grapheme, current_col) {
            // 分支1：需要替换（普通空格/制表符/非普通空白符）
            Some((rep_str, width)) => (Some(rep_str), width),
            // 分支2：无需替换（零宽字符/普通可见字符）→ 用原字素的 Unicode 宽度
            None => {
                let unicode_width = grapheme.width();
                (None, GraphicCellWidth::from_usize(unicode_width))
            }
        };

        Self {
            content: grapheme.to_string(),
            rendering_width,
            replacement,
            start,
        }
    }
}
